iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0
Modern Web

30 days of React 系列 第 29

Day 29 - React useEffect cleanup function 練習:製作電子時鐘

  • 分享至 

  • xImage
  •  

昨天我們學習了副作用相關的知識,並嘗試使用useEffect完成了一個小練習,但還沒有使用到cleanup function。今天要透過實作的練習來學習Cleanup function的相關知識。

今天會學到的東西:

  • Cleanup funciton是什麼
  • 為什麼需要Cleanup function

電子時鐘

現有的程式碼:

  • App.js
import React from 'react';

import Clock from './Clock'

function App() {
  const [showClock, setShowClock] = React.useState(true);

  return (
    <>
      <button
        className="clock-toggle"
        onClick={() => setShowClock(!showClock)}
      >
        {showClock ? 'Clock ON' : 'Clock OFF'}
      </button>

      {showClock && <Clock />}
    </>
  );
}

export default App;
  • Clock.js
import React from 'react';
import format from 'date-fns/format';

function Clock() {
  const [time, setTime] = React.useState(new Date());

  return (
    <p className="clock">
      {format(time, 'hh:mm:ss a')}
    </p>
  );
}

export default Clock;

本次的練習僅需要操作Clock.js 的檔案即可。

  • 現有的畫面:

畫面是這個樣子,當點擊按鈕時,會顯示/隱藏 電子時鐘。

像這樣子時鐘會被隱藏,要做到一旦顯示時,則時鐘正常的運作。

操作步驟

Step 1 : 創建useEffect function

要做時鐘我們會用到的有setInterval,而setInterval的操作也是屬於副作用的一種,因此需要使用useEffect function。


  React.useEffect(()=> {
    //要執行的程式碼
  }, [])

因為希望當點擊按鈕時,電子時鐘出現,這樣子的情況應採用dependencies 為 [] empty string的作法,也就是「程式碼僅在**掛載(mounting)時執行(當元件出現時)」(這部分昨天的文章有提到)。

Step 2: 編寫內部的邏輯

  React.useEffect(()=> {
    const intervalID = window.setInterval(()=> {
      setTime(new Date());
    }, 1000)
  }, [])

在內部使用了一個定時器(setInterval),每隔一秒執行一次,讓每秒能夠更新一次時間。

目前為止電子時鐘看起來似乎正常運作了,也顯示了正確的時間。

但當我們把時鐘收合起來,程式碼真的就沒有在運作了嗎?

讓我們在setInterval當中測試看看:

  React.useEffect(()=> {
    const intervalID = window.setInterval(()=> {
      console.log('滴答');
      setTime(new Date());
    }, 1000)
  }, [])

加入了秒針的滴答聲,接下來把時鐘收合起來看看:

可以發現即使把按鈕收合起來,仍然在「滴答滴答~」,也就是setInterval 還在運作中,並沒有因為將按鈕收合起來而停止運作。

為什麼會這樣子呢?如果是unmount 不是應該要自動被卸載嗎?

這是因為React其實不知道useEffect內部發生什麼事,當在一個元件中使用了useEffect處理副作用,元件渲染時,React並不知道內部做了什麼事情。它只知道在指定的時機(由設定的dependencies)來呼叫我們寫在useEffect中的function。

對React 而言,React看到的就是這樣子:

// React看見的世界:
React.useEffect(() => {
  ????
}, []);

因為React並不知道,因此需要另外設置讓setInterval停止的操作,需要cleanUp function來設定。

Step 3: 設置cleanUp function

cleanup function的寫法是透過在useEffect function中 return function來處理:

   return () => {
// function的內容
    };

那我們來加上cleanup function到電子時鐘上:

 React.useEffect(() => {
    const intervalID = window.setInterval(() => {
      console.log('滴答');
      setTime(new Date());
    }, 1000);
    return () => {
      clearInterval(intervalID)
    }
  }, []);

再來觀察看看關閉電子時鐘還會有滴答聲嗎?

滴答聲消失了,這代表我們成功clearInterval,這樣就完成電子時鐘。

以上是今天的練習,今天學到為什麼需要cleanup function以及練習了cleanup function的寫法。

雖然在這個時鐘案例我們使用了cleanup function,但並不是每次操作useEffect都需要 cleanup function的操作,cleanup function通常用在訂閱事件、設置定時器、綁定事件監聽器等的操作,而像是一次性操作或是有外部自動清理機制的操作等並不需要cleanup function。

(本日練習出自The Joy of React)

參考資料

  • The Joy of React - Cleanup
  • The Joy of React - Cleanup exercises
  • React 官方文件 - Synchronizing with Effects

上一篇
Day 28 - React useEffect 基礎:Focus a field on mount 實作練習
下一篇
Day 30 - 系列回顧、檢討會、知識管理與學習
系列文
30 days of React 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言